<?php

// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2010 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: luofei614 <www.3g4k.com>
// +----------------------------------------------------------------------
// $Id: SaeStorage.class.php 2803 2012-03-06 14:57:17Z luofei614@gmail.com $
/**
 * storage模拟器
 * 在本地环境时，domain对应了Public文件夹下以domain名命名的的文件夹
 */
//本地默认的域在public中， 建立的文件夹名为域名。
class SaeStorage extends SaeObject {
	
	private $domainDir; //域的根目录
	private $filterPath;
	private $url;
	private $domainSize = array (); //记录域大小
	private $domainSizeFlag = "";
	
	//todu 增加api文档没有的函数
	public function __construct($_accessKey = '', $_secretKey = '') {
		global $sae_config;
		$this->domainDir = $sae_config ['storage_dir'];
		$this->url = $sae_config ['storage_url'];
		parent::__construct ();
	}
	
	public function delete($domain, $filename) {
		$domain = trim ( $domain );
		$filename = $this->formatFilename ( $filename );
		if (Empty ( $domain ) || Empty ( $filename )) {
			$this->errMsg = Imit_L ( "_SAE_STORAGE_PARAM_EMPTY_" ) . '[the value of parameter (domain,filename) can not be empty!]';
			$this->errNum = - 101;
			return false;
		}
		$filepath = $this->domainDir . $domain . "/" . $filename;
		if (unlink ( $filepath )) {
			return true;
		} else {
			$this->errno = - 1;
			$this->errmsg = Imit_L ( "_SAE_STORAGE_DELETE_ERR_" );
			return false;
		}
	}
	
	public function deleteFolder($domain, $path) {
		$domain = trim ( $domain );
		$path = $this->formatFilename ( $path );
		if (Empty ( $domain ) || Empty ( $path )) {
			$this->errmsg = Imit_L ( "_SAE_STORAGE_PARAM_EMPTY_" ) . '[the value of parameter (domain,path) can not be empty!]';
			$this->errno = - 101;
			return false;
		}
		$folder = $this->domainDir . $domain . "/" . $path;
		$this->delDir ( $folder );
		return true;
	}
	
	private function delDir($directory) {
		if (is_dir ( $directory ) == false) {
			exit ( "The Directory Is Not Exist!" );
		}
		$handle = opendir ( $directory );
		while ( ($file = readdir ( $handle )) !== false ) {
			if ($file != "." && $file != "..") {
				is_dir ( "$directory/$file" ) ? $this->delDir ( "$directory/$file" ) : unlink ( "$directory/$file" );
			}
		}
		if (readdir ( $handle ) == false) {
			closedir ( $handle );
			rmdir ( $directory );
		}
	}
	
	public function fileExists($domain, $filename) {
		$domain = trim ( $domain );
		$filename = $this->formatFilename ( $filename );
		if (Empty ( $domain ) || Empty ( $filename )) {
			$this->errmsg = Imit_L ( "_SAE_STORAGE_PARAM_EMPTY_" ) . '[the value of parameter (domain,filename) can not be empty!]';
			$this->errno = - 101;
			return false;
		}
		$filepath = $this->domainDir . $domain . "/" . $filename;
		return file_exists ( $filepath );
	}
	
	public function getAttr($domain, $filename, $attrKey = array()) {
		$filepath = $this->domainDir . $domain . "/" . $filename;
		if (! is_file ( $filepath )) {
			$this->errno = - 1;
			$this->errmsg = Imit_L ( "_SAE_STORAGE_FILE_NOT_EXISTS_" );
			return false;
		}
		if (empty ( $attrKey ))
			$attrKey = array ('fileName', 'length', 'datetime' );
		$ret = array ();
		foreach ( $attrKey as $key ) {
			switch ($key) {
				case "fileName" :
					$ret ['fileName'] = $filename;
					break;
				case "length" :
					$ret ['length'] = filesize ( $filepath );
					break;
				case "datetime" :
					$ret ['datetime'] = filemtime ( $filepath ); //todu 需要验证一下
					break;
			}
		}
		return $ret;
	}
	
	public function getDomainCapacity($domain) {
		if (! isset ( $this->domainSize [$domain] ))
			$this->getList ( $domain );
		return $this->domainSize [$domain];
	}
	
	public function getFilesNum($domain, $path = NULL) {
		static $filesNum = array ();
		if (isset ( $filesNum [md5 ( $domin . $path )] ))
			return $filesNum [md5 ( $domin . $path )];
		if ($path == NULL)
			$path = "*";
		$filesNum [md5 ( $domin . $path )] = count ( $this->getList ( $domain, $path ) );
		return $filesNum [md5 ( $domin . $path )];
	}
	
	public function getList($domain, $prefix = '*', $limit = 10, $offset = 0) {
		$domain = trim ( $domain );
		if (Empty ( $domain )) {
			$this->errMsg = Imit_L ( "_SAE_STORAGE_PARAM_EMPTY_" ) . '[the value of parameter (domain) can not be empty!]';
			$this->errNum = - 101;
			return false;
		}
		$path = $this->domainDir . $domain;
		$this->filterPath = $path . "/";
		//记录域的大小
		if ($prefix == "*" && ! isset ( $this->domainSize [$domain] ))
			$this->domainSizeFlag = $domain;
		$files = $this->getAllList ( $path, $prefix );
		$this->domainSizeFlag = "";
		//偏移
		return array_slice ( $files, $offset, $limit );
	}
	
	//获得所有文件
	private function getAllList($path, $prefix, &$files = array()) {
		$list = glob ( $path . "/" . $prefix );
		//循环处理，创建数组
		$dirs = array ();
		$_files = array ();
		foreach ( $list as $i => $file ) {
			if (is_dir ( $file ) && ! $this->isEmpty ( $file )) { //如果不是空文件夹
				$dirs [] = $file;
				continue;
			}
			;
			if (! empty ( $this->domainSizeFlag ))
				$this->domainSize [$this->domainSizeFlag] += filesize ( $file ); //统计大小
			

			$_files [$i] ['name'] = str_replace ( $this->filterPath, '', $file ); //不含域的名称
			$_files [$i] ['isDir'] = is_dir ( $file );
		}
		//排序$_files
		$cmp_func = create_function ( '$a,$b', '
			$k="isDir";
			if($a[$k]  ==  $b[$k])  return  0;
			return  $a[$k]>$b[$k]?-1:1;
			' );
		usort ( $_files, $cmp_func );
		foreach ( $_files as $file ) {
			//设置$files
			$files [] = $file ['isDir'] ? $file ['name'] . "/__________sae-dir-tag" : $file ['name'];
		}
		//循环数组，读取二级目录
		foreach ( $dirs as $dir ) {
			$this->getAllList ( $dir, "*", $files );
		}
		return $files;
	}
	
	//判断是否为空目录
	private function isEmpty($directory) {
		$handle = opendir ( $directory );
		while ( ($file = readdir ( $handle )) !== false ) {
			if ($file != "." && $file != "..") {
				closedir ( $handle );
				return false;
			}
		}
		closedir ( $handle );
		return true;
	}
	
	public function getListByPath($domain, $path = NULL, $limit = 100, $offset = 0, $fold = true) {
		$filepath = $this->domainDir . $domain . "/" . $path;
		$list = scandir ( $filepath );
		//读取非折叠数据
		$files = array ();
		$dirnum = 0;
		$filenum = 0;
		foreach ( $list as $file ) {
			//统计
			if ($file == '.' || $file == '..')
				continue;
			$fullfile = $filepath . "/" . $file;
			if (is_dir ( $fullfile )) {
				$dirnum ++;
				$filename = $fullfile . "/__________sae-dir-tag";
			} else {
				$filenum ++;
				$filename = $fullfile;
			}
			
			$filename = str_replace ( $this->domainDir . $domain . "/", '', $filename );
			
			$files [] = array ('name' => basename ( $filename ), 'fullName' => $filename, 'length' => filesize ( $fullfile ), 'uploadTime' => filectime ( $fullfile ) );
		}
		//偏移
		$files = array_slice ( $files, $offset, $limit );
		if ($fold) {
			//折叠处理
			$rets = array ('dirNum' => $dirnum, 'fileNum' => $filenum );
			foreach ( $files as $file ) {
				if ($file ['name'] == "__________sae-dir-tag") {
					//文件夹
					$rets ['dirs'] [] = array ('name' => $file ['name'], 'fullName' => $file ['fullName'] );
				} else {
					$rets ['files'] [] = $file;
				}
			}
			return $rets;
		}
		return $files;
	}
	
	public function getUrl($domain, $filename) {
		$domain = trim ( $domain );
		$filename = $this->formatFilename ( $filename );
		return $this->url . $domain . "/" . $filename;
	}
	
	public function read($domain, $filename) {
		$domain = trim ( $domain );
		$filename = $this->formatFilename ( $filename );
		if (Empty ( $domain ) || Empty ( $filename )) {
			$this->errmsg = Imit_L ( "_SAE_STORAGE_PARAM_EMPTY_" ) . '[the value of parameter (domain,filename) can not be empty!]';
			$this->errno = - 101;
			return false;
		}
		$filepath = $this->domainDir . $domain . "/" . $filename;
		return file_get_contents ( $filepath );
	}
	
	public function setDomainAttr($domain, $attr = array()) {
		//pass
		return true;
	}
	
	public function setFileAttr($domain, $filename, $attr = array()) {
		//pass
		return true;
	}
	
	public function upload($domain, $destFileName, $srcFileName, $attr = array()) {
		$domain = trim ( $domain );
		$destFileName = $this->formatFilename ( $destFileName );
		if (Empty ( $domain ) || Empty ( $destFileName ) || Empty ( $srcFileName )) {
			$this->errmsg = Imit_L ( "_SAE_STORAGE_PARAM_EMPTY_" ) . '[the value of parameter (domain,destFile,srcFileName) can not be empty!]';
			$this->errno = - 101;
			return false;
		}
		return $this->write ( $domain, $destFileName, file_get_contents ( $srcFileName ) );
	}
	
	public function write($domain, $destFileName, $content, $size = -1, $attr = array(), $compress = false) {
		if (Empty ( $domain ) || Empty ( $destFileName )) {
			$this->errmsg = Imit_L ( "_SAE_STORAGE_PARAM_EMPTY_" ) . "[the value of parameter (domain,destFileName,content) can not be empty!]";
			$this->errno = - 101;
			return false;
		}
		//定义文件路径
		$filepath = $this->domainDir . $domain . "/" . $destFileName;
		$this->mkdir ( dirname ( $filepath ) );
		//设置长度
		if ($size > - 1)
			$content = substr ( $content, 0, $size );
		
		//写入文件
		if (file_put_contents ( $filepath, $content )) {
			return true;
		} else {
			$this->errmsg = Imit_L ( '_SAE_STORAGE_SERVER_ERR_' );
			$this->errno = - 12;
			return false;
		}
	}
	
	//创建目录，无限层次。传递一个文件的
	private function mkdir($dir) {
		static $_dir; // 记录需要建立的目录
		if (! is_dir ( $dir )) {
			if (empty ( $_dir ))
				$_dir = $dir;
			if (! is_dir ( dirname ( $dir ) )) {
				$this->mkdir ( dirname ( $dir ) );
			} else {
				mkdir ( $dir );
				if (! is_dir ( $_dir )) {
					$this->mkdir ( $_dir );
				} else {
					$_dir = "";
				}
			}
		}
	}
	
	private function formatFilename($filename) {
		$filename = trim ( $filename );
		
		$encodings = array ('UTF-8', 'GBK', 'BIG5' );
		
		$charset = mb_detect_encoding ( $filename, $encodings );
		if ($charset != 'UTF-8') {
			$filename = mb_convert_encoding ( $filename, "UTF-8", $charset );
		}
		
		return $filename;
	}

}

?>